/**
 * 
 */
package com.xxl.job.admin.core.util;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;

/**
 * 描述：
 * 
 * <pre>
 * 执行SQL文件进行建表
 * </pre>
 * 
 * @author qizai
 * @version: 0.0.1 2021年2月24日-下午1:44:45
 *
 */
public class TableInitialization {
	private static final String	INIT_DB_FILE	= "sql/init_xxl_job.sql";
	private static final String	CHECK_DB_SQL	= "SELECT COUNT(*) FROM xxl_job_info";
	private static Logger		log				= LoggerFactory.getLogger(TableInitialization.class);

	private static String toStringSafe(final InputStream input) {
		if (null == input) {
			return null;
		}
		ByteArrayOutputStream result = new ByteArrayOutputStream();
		byte[] buffer = new byte[2048];
		int length;
		try {
			while ((length = input.read(buffer)) != -1) {
				result.write(buffer, 0, length);
			}
			return result.toString(StandardCharsets.UTF_8.name());
		} catch (IOException e) {
			// TODO Auto-generated catch block
		}
		return null;
	}

	public static void init(DataSource pool) {
		int exists = executeCount(pool, CHECK_DB_SQL);
		if (exists != -1) {
			log.info("Table is exists!");
			return;
		}
		try {
			ClassPathResource classPathResource = new ClassPathResource(INIT_DB_FILE);
			if (classPathResource.exists() && classPathResource.isReadable()) {
				try (InputStream in = classPathResource.getInputStream()) {
					int updateSize = executeUpdate(pool, toStringSafe(in));
					log.info("Table Create Success= {}", updateSize);
				}
			} else {
				log.warn("Table Create Error File={} is not read", INIT_DB_FILE);
			}
		} catch (Exception e) {
			log.warn("Table Create Error !", e.getMessage());
		}
	}

	/**
	 * 
	 * @param pool
	 *            链接池
	 * @param sql
	 *            COUNT SQL 可以带有 ? 的占位符
	 * @param params
	 *            插入到 SQL 中的参数，可单个可多个可不填
	 * @return 进行COUNT查询，异常返回-1
	 */
	private static int executeCount(DataSource pool, String sql, Object... params) {
		try (final Connection connection = pool.getConnection()) {
			try (final PreparedStatement statement = connection.prepareStatement(sql)) {
				if (params != null) {
					for (int i = 0; i < params.length; i++)
						statement.setObject(i + 1, params[i]);
				}
				try (ResultSet rs = statement.executeQuery(sql)) {
					while (rs.next()) {
						return rs.getInt(1);
					}
				}
			}
		} catch (SQLException e) {
			log.info("selectCount SQLException:{}", e.getMessage());
		}
		return -1;
	}

	private static int executeUpdate(DataSource pool, String sql, Object... params) {
		try (final Connection connection = pool.getConnection()) {
			try (final PreparedStatement statement = connection.prepareStatement(sql)) {
				if (params != null) {
					for (int i = 0; i < params.length; i++)
						statement.setObject(i + 1, params[i]);
				}
				return statement.executeUpdate();
			}
		} catch (SQLException e) {
			log.info("executeUpdate SQLException:{}", e.getMessage());
		}
		return -1;
	}
}
